#pragma once 

#include <iostream>
#include <queue>
#include <pthread.h>


template <class T>
class ThreadPool{
    private:
        std::queue<T> q; //给线程池派发任务的地点, 临界资源
        pthread_mutex_t lock;
        pthread_cond_t cond;
    private:
        ThreadPool()
        {
            pthread_mutex_init(&lock, nullptr);
            pthread_cond_init(&cond, nullptr);
        }
        ThreadPool(const ThreadPool<T>&) = delete;
        ThreadPool<T>& operator = (const ThreadPool<T>&) = delete;
        static ThreadPool<T> *instance;
    public:
        static ThreadPool<T> *get_instance(int num)
        {
            //static std::mutex lock;
            //lock.lock();
            static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
            if(nullptr == instance){
                pthread_mutex_lock(&mtx);
                if(nullptr == instance){
                    instance = new ThreadPool<T>();
                    instance->InitThreadPool(num);
                    //instance->Init...
                }
                pthread_mutex_unlock(&mtx);
            }
            //lock.unlock();
            return instance;
        }
        void LockQueue()
        {
            pthread_mutex_lock(&lock);
        }
        void UnlockQueue()
        {
            pthread_mutex_unlock(&lock);
        }
        bool IsEmpty()
        {
            return q.size() == 0;
        }
        void ThreadWait()
        {
            pthread_cond_wait(&cond, &lock);
        }
        void ThreadWakeup()
        {
            pthread_cond_signal(&cond);
        }
        void PopTask(T *out)
        {
            *out = q.front();
            q.pop();
        }
        //Routinue是类中的一个成员方法！包含了一个隐士参数this！ThreadPool*
        //实际上，这里是包含了两个参数的！
        static void *Routinue(void *args/*,ThreadPool *this*/)
        {
            pthread_detach(pthread_self()); //线程分离
            ThreadPool *tp = (ThreadPool*)args;

            while(true){
                tp->LockQueue();
                //1. 检测是否有任务
                //if -> while
                while(tp->IsEmpty()){
                    //thread 应该等待,等待有任务
                    tp->ThreadWait(); //我们线程当前是在临界区内等待的！我是持有锁的！！！
                }
                //2. 取任务的过程
                T t;
                tp->PopTask(&t);
                tp->UnlockQueue();
                //3. 处理任务, 拿到任务之后，处理任务的时候，需要在临界区内处理吗？不需要
                //在你的线程处理任务期间，其他线程是不是可以继续获取任务，处理任务
                t();
            }
        }
        void InitThreadPool(int num)
        {
            for(auto i = 0; i < num; i++){
                pthread_t tid;
                pthread_create(&tid, nullptr, Routinue, this);
            }
        }
        void PushTask(const T &in)
        {
            //放任务
            LockQueue();
            q.push(in);
            ThreadWakeup();
            UnlockQueue();
        }

        ~ThreadPool()
        {
            pthread_mutex_destroy(&lock);
            pthread_cond_destroy(&cond);
        }
};

template<class T>
ThreadPool<T>* ThreadPool<T>::instance = nullptr;


